/*bcos c sdk的javascript ffi 封装
* 2023.04.20，会有运行时多线程问题, 先放一放
* */
const ffi = require('ffi-napi');
const ref = require('ref-napi');
const StructType = require('ref-struct-napi');
// 定义 C 函数返回类型
const CString = ref.types.CString;
const Int64 = ref.types.int64;


// 定义 C 函数返回类型
const VoidPtr = ref.refType(ref.types.void);
// 定义bcos_sdk_create函数的参数和返回值类型
const bcos_sdk_create = ffi.Function('void*', ['string']);

const bcosSdkStart = ffi.Function('void', [VoidPtr]);

var configfile = "./bcos3sdklib/bcos3_sdk_config.ini\0";
var config = Buffer.alloc(1024,configfile); // 假设这是一个合法的结构体

function sleep(delay) {
    var start = (new Date()).getTime();
    while ((new Date()).getTime() - start < delay) {
        // 使用  continue 实现；
        continue;
    }
}

// 定义结构体
const BcosSdkCStructResponse = StructType({
  error: 'int',
  desc: CString,
  data: CString,
  size: Int64,
  context: "pointer",
});
;

//void bcos_rpc_get_block_by_number(void* sdk, const char* group, const char* node, int64_t block_number, int only_header, int only_tx_hash, bcos_sdk_c_struct_response_cb callback, void* context)
// 打开dll库
const bcos3lib = ffi.Library('./bcos3sdklib/bcos-c-sdk.dll', {
    'bcos_sdk_create_by_config_file': [VoidPtr, [ref.types.CString]],
    'bcos_sdk_version': [CString, []],
    'bcos_sdk_start': ['void', [VoidPtr]],
    'bcos_rpc_get_block_limit': [Int64, [VoidPtr, CString]],
    'bcos_sdk_get_last_error': [ 'int', [] ],
    'bcos_sdk_get_last_error_msg': [CString, [VoidPtr]],
    'bcos_rpc_get_block_number': ['void',
    [VoidPtr, CString, CString, VoidPtr, VoidPtr],
    ],
    'bcos_rpc_get_block_by_number':['void',
        [VoidPtr, CString, CString,Int64,Int64,'int', VoidPtr, VoidPtr],
    ]
});

const group = 'group0'; // 要查询的群组名称
var node= ''
console.log("bcos3lib:",bcos3lib)
// 调用 C 函数并获取返回值
const version = bcos3lib.bcos_sdk_version();
console.log("c return version is:",version)

// 准备函数参数
console.log("start create by:",configfile)
// 调用bcos_sdk_create函数
var bcos_sdk_ptr = bcos3lib.bcos_sdk_create_by_config_file(configfile);
console.log("bcos_sdk_ptr",bcos_sdk_ptr)
bcos3lib.bcos_sdk_start(bcos_sdk_ptr)
var blockLimit = bcos3lib.bcos_rpc_get_block_limit(bcos_sdk_ptr,group)
console.log("blocklimit:",blockLimit)
var errmsg = bcos3lib.bcos_sdk_get_last_error_msg(bcos_sdk_ptr)
console.log("errmsg:",errmsg)
var sn = 100;
const context = null;  // 可以传入一个上下文对象

process.on('uncaughtException', function (err) {
  //打印出错误
  console.log(err);
  //打印出错误的调用栈方便调试
  console.log(err.stack);
});

var counter = 0;

function dealResponse(resp) {
           counter++;
           console.log('callback function called [ %d ]',counter);
           //return;
            //return;
            console.log("-------------------")
            console.log('>> error:', resp.deref().error);
            console.log('>> desc:', resp.deref().desc);
            //console.log('>> rawdata:', resp.deref().data);
            var datasize = resp.deref().size;
            var str = resp.deref().data;
            str = str.substring(0,datasize);

            console.log("--->data: ", str)
            //const str = ref.readCString(resp.deref().data);;
            //console.log('>> data:',str );
            //console.log('>> size:', resp.deref().size);
            //console.log('>> context:', resp.deref().context);
            console.log("-------------------")
      }
      /*
const callbackWrapper = () => {
  process.nextTick(dealResponse);
};*/
async function callrpc() {
    console.log("callrpc start");

    // 定义回调函数类型
    const BcosSdkCStructResponseCb = ffi.Callback(
      ref.types.void,
      [ref.refType(BcosSdkCStructResponse)],
      dealResponse
    );

    try {

        bcos3lib.bcos_rpc_get_block_number(bcos_sdk_ptr, group, node, BcosSdkCStructResponseCb, context);
        sleep(5000);
        //console.log("go bcos_rpc_get_block_by_number");

        bcos3lib.bcos_rpc_get_block_by_number(bcos_sdk_ptr, group, node, 10, 0, 0, BcosSdkCStructResponseCb, context)
        sleep(5000);
    }catch(e){
        console.log("rpccall exception:",e)
    }
     //sleep(2000);

}

//多次调用必挂，大概原因是bcos_c_sdk里的回调是多线程的而nodejs是单线程模型的，
//todo:c-sdk 以后提供promise或future模式的单线程模型接口，由nodejs自己调度
callrpc();
callrpc();
callrpc();
callrpc();
callrpc();



sleep(3000);